/* Vecmath.

   Copyright (C) 2001, 2002, 2003 Stefan Maierhofer.

   Written by Stefan Maierhofer <sm@cg.tuwien.ac.at>

   This file is part of Vecmath.

   Vecmath is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 2 of the License, or
   (at your option) any later version.

   Vecmath is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with Vecmath; if not, write to the Free Software Foundation,
   Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. */

using System;
using NUnit.Framework;

namespace Vecmath.Shapes
{

    /// <summary>
    /// Triangle3D.
    /// </summary>
    public struct Triangle3D
    {

        public Triangle3D(Pnt3D a, Pnt3D b, Pnt3D c)
        {
            p0 = a; p1 = b; p2 = c;
        }

        public Pnt3D this [int index]
        {
            get
            {
                switch (index)
                {
                    case 0: return p0;
                    case 1: return p1;
                    case 2: return p2;
                    default: return p0;
                }
            }
            set
            {
                switch (index)
                {
                    case 0: p0 = value; break;
                    case 1: p1 = value; break;
                    case 2: p2 = value; break;
                }
            }
        }

        public bool Intersect(
            Ray3D ray, ref double t, ref double u, ref double v, ref Vec3D normal
            )
        {
            Vec3D e1 = p1 - p0;
            Vec3D e2 = p2 - p0;
            Vec3D p = Vec3D.Cross(ray.Direction, e2);

            double a = Vec3D.Dot(e1, p);
            if (a > -Vecmath.TINY_DOUBLE && a < Vecmath.TINY_DOUBLE) return false;
            double f = 1.0 / a;
            Vec3D s = ray.Point - p0;
            u = f * Vec3D.Dot(s, p);
            if (u < 0.0 || u > 1.0) return false;
            Vec3D q = Vec3D.Cross(s, e1);
            v = f * Vec3D.Dot(ray.Direction, q);
            if (v < 0.0 || (u + v) > 1.0) return false;
            t = f * Vec3D.Dot(e2, q);
            normal = Vec3D.Cross(e1, e2); normal.Normalize();
            return true;
        }

        public Pnt3D p0;
        public Pnt3D p1;
        public Pnt3D p2;

    }

}
